using System;

using Microsoft.Cci;
using Microsoft.FxCop.Sdk.Introspection;
using Microsoft.FxCop.Sdk;

namespace JSL.FxCop
{
    /// <summary>
    /// Finds and flags try/catches that don't do anything.
    /// </summary>
    public class RemoveUselessCatch : JSLBaseIntrospectionRule
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="RemoveUselessCatch"/> class.
        /// </summary>
        public RemoveUselessCatch()
            : base(typeof(RemoveUselessCatch))
        {
        }
        #endregion Constructors

        #region Public Methods
        /// <summary>
        /// Checks each instruction of the method.
        /// </summary>
        /// <param name="method">The method.</param>
        /// <param name="instructionIndex">Index of the instrucion.</param>
        /// <param name="instruction">The instruction.</param>
        /// <returns>The problems found if any.</returns>
        public override ProblemCollection Check(Method method, int instructionIndex, Instruction instruction)
        {
            // We only care about catch OpCodes.
            if (instruction.OpCode != OpCode._Catch)
            {
                return null;
            }

            bool hasRethrow = false;
            for (int nextInstructionIndex = instructionIndex + 1; nextInstructionIndex < method.Instructions.Length; nextInstructionIndex++)
            {
                Instruction nextInstruction = method.Instructions[nextInstructionIndex];

                switch (nextInstruction.OpCode)
                {
                    case OpCode._EndHandler:
                        if (hasRethrow)
                        {
                            this.Problems.Add(new Problem(this.GetResolution(), instruction.SourceContext));
                        }
                        return this.Problems;
                        
                    case OpCode.Rethrow:
                        hasRethrow = true;
                        break;

                    case OpCode.Nop:
                    case OpCode.Pop:
                        break;

                    default:
                        // If any other opcode is found then this isn't a "useless" catch.
                        return null;
                }
            }

            return null;
        }
        #endregion Public Methods
    }
}